入れ子になった React Component を TDD で実装する
以下の複数の DOM 要素をレンダリングするコンポーネントを TDD で実装する <figure>
<img>
<figcaption>
<strong>
Step 1: 定義
テストを書く
code:CarouselSlide.test.tsx
describe("CarouselSlide", () => {
it("renders a <figure>", () => {
render(<CarouselSlide />);
expect(screen.getByRole("figure")).toBeInTheDocument();
});
});
テストをパスする最低限の実装を書く
code:CarouselSlide.tsx
const CarouselSlide = () => <figure />;
export default CarouselSlide;
Step 2: <figure> に 2 つの子要素(<img> と <figcaption>)を含める
テストを書く
code:CarouselSlide.test.tsx
it("renders an <img> and a <figcaption>", () => {
render(<CarouselSlide />);
const figure = screen.getByRole("figure");
const img = screen.getByRole("img");
const figcaption = screen.getByTestId("caption");
expect(figure).toContainElement(img);
expect(figure).toContainElement(figcaption);
});
<figcaption> は 暗黙の ARIA ロール が無いため、getByTestId でテスト ID を用いて要素を取得している テストをパスする最低限の実装を書く
code:CarouselSlide.tsx
const CarouselSlide = () => <figure />;
export default CarouselSlide;
Step 3: 表示する画像の URL を Props で受け取る テストを書く
code:CarouselSlide.test.tsx
it("passes imgUrl through to the <img>", () => {
render(<CarouselSlide imgUrl={imgUrl} />);
expect(screen.getByRole("img")).toHaveAttribute("src", imgUrl);
});
テストをパスする最低限の実装を書く
code:CarouselSlide.tsx
const CarouselSlide = ({ imgUrl }: { imgUrl?: string }) => (
<figure>
<img src={imgUrl} />
<figcaption data-testid="caption" />
</figure>
);
Step 4: 画像のキャプションにセットするテキストと作者名を Props で受け取る
テストを書く
code:CarouselSlide.test.tsx
it("uses description and attribution as the caption", () => {
const props = {
description: "A jaw-droppingly spectacular image",
attribution: "Trevor Burnham",
};
render(<CarouselSlide {...props} />);
const figcaption = screen.getByTestId("caption");
expect(figcaption).toHaveTextContent(
${props.description} ${props.attribution},
);
});
テストをパスする最低限の実装を書く
code:CarouselSlide.tsx
const CarouselSlide = ({
imgUrl,
description,
attribution,
}: {
imgUrl?: string;
description?: ReactNode;
attribution?: ReactNode;
}) => (
<figure>
<img src={imgUrl} />
<figcaption data-testid="caption">
<strong>{description}</strong> {attribution}
</figcaption>
</figure>
);
Step 5: <figure> 要素がサポートするすべての Props を受け取れるようにする
テストを書く
code:CarouselSlide.test.tsx
it("passes other props through to the <figure>", () => {
const className = "my-carousel-slide";
const dataAction = "prev";
render(<CarouselSlide className={className} data-action={dataAction} />);
const figure = screen.getByRole("figure");
expect(figure).toHaveClass(className);
expect(figure).toHaveAttribute("data-action", dataAction);
});
テストをパスする最低限の実装を書く
code:CarouselSlide.tsx
const CarouselSlide = ({
imgUrl,
description,
attribution,
...rest
}: {
imgUrl?: string;
description?: ReactNode;
attribution?: ReactNode;
} & ComponentPropsWithRef<"figure">) => (
<figure {...rest}>
<img src={imgUrl} />
<figcaption data-testid="caption">
<strong>{description}</strong> {attribution}
</figcaption>
</figure>
);